package com.testcolision.simulation;

import java.util.Random;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes;

/*
 * Extended Terrain class created by Mario Zechner
 * 
 */

public class Terrain {

	public final byte[] heightMap;
	public final short width;
	public final short height;
	public final float[] vertices;
	public final short[] indices;
	public final int vertexSize;
	public float stepSize;
	public Mesh terrainMesh;

	public Terrain(int width, int height, int vertexSize, int stepSize) {
		if ((width + 1) * (height + 1) > Short.MAX_VALUE)
			throw new IllegalArgumentException("Chunk size too big, (width + 1)*(height+1) must be <= 32767");

		this.heightMap = new byte[(width + 1) * (height + 1)];
		this.width = (short) width;
		this.height = (short) height;
		this.vertices = new float[heightMap.length * vertexSize];
		this.indices = new short[width * height * 6];
		this.vertexSize = vertexSize;
		this.stepSize = stepSize;
		buildHeightMap();
		buildIndices();
		buildVertices();
		createTerrainMesh();
	}

	// TODO build from file
	// TODO texture
	private void buildHeightMap() {
		Random rand = new Random();
		int idx = 0;
		for (int i = 0; i < height + 1; i++) {
			for (int j = 0; j < width + 1; j++) {
			 heightMap[idx++] = (byte) (-4 + rand.nextFloat() * 8);
// 			heightMap[idx++] = (byte) 0;			
				}

		}
	}

	public void buildVertices() {
		int heightPitch = height + 1;
		int widthPitch = width + 1;

		int idx = 0;
		int hIdx = 0;
		int inc = vertexSize - 3;

		for (int z = 0; z < heightPitch; z++) {
			for (int x = 0; x < widthPitch; x++) {
				vertices[idx++] = x * stepSize;
				vertices[idx++] = heightMap[hIdx++];
				vertices[idx++] = z * stepSize;
				idx += inc;
			}
		}
	}

	private void buildIndices() {
		int idx = 0;
		short pitch = (short) (width + 1);
		short i1 = 0;
		short i2 = 1;
		short i3 = (short) (1 + pitch);
		short i4 = pitch;

		short row = 0;

		for (int z = 0; z < height; z++) {
			for (int x = 0; x < width; x++) {

				// i1 ____i2
				// \ |
				// \ |
				// \|
				// i3

				indices[idx++] = i1;
				indices[idx++] = i2;
				indices[idx++] = i3;

				// i1
				// |\
				// | \
				// |__\
				// i4 i3
				indices[idx++] = i3;
				indices[idx++] = i4;
				indices[idx++] = i1;

				i1++;
				i2++;
				i3++;
				i4++;
			}

			row += pitch;
			i1 = row;
			i2 = (short) (row + 1);
			i3 = (short) (i2 + pitch);
			i4 = (short) (row + pitch);
		}
	}

	private void createTerrainMesh() {

		int len = vertices.length;
		for (int i = 3; i < len; i += 6)
			vertices[i] = Color.toFloatBits(255, 255, 255, 255);

		float uvStepSize = 1.0f / width;
		// Gdx.app.log("", ""+uvStepSize);
		short idx = 0;
		short row = 0;
		for (int j = 0; j < height + 1; j++) {
			for (int i = (width * row * 6) + 4; i < (width * 6 * row) + (width * 6) + 6; i += 6) {
				vertices[i] = uvStepSize * idx;
				vertices[i + 1] = uvStepSize * row;
				// Gdx.app.log("U:" +uvStepSize * idx, "/ V: "+ uvStepSize *
				// row);
				idx++;
			}

			idx = 0;
			row++;
		}

		terrainMesh = new Mesh(true, vertices.length / 3, indices.length, new VertexAttribute(VertexAttributes.Usage.Position, 3, "a_position"), new VertexAttribute(
				VertexAttributes.Usage.ColorPacked, 4, "a_color"), new VertexAttribute(VertexAttributes.Usage.TextureCoordinates, 2, "a_texCoords"));

		terrainMesh.setVertices(vertices);
		terrainMesh.setIndices(indices);

	}
}